package com.gitee.apanlh.util.unit;

import com.gitee.apanlh.exp.UnknownTypeException;
import com.gitee.apanlh.util.base.BigDecimalUtils;
import com.gitee.apanlh.util.base.StringUtils;
import com.gitee.apanlh.util.valid.Assert;
import com.gitee.apanlh.util.valid.ValidParam;

/**
 * 	长度单位枚举
 * 	<br>用于转换长度单位使用{@link DataSize}
 * 	
 * 	@author Pan
 */
public enum DataSizeUnit {
	
	NO_SYMBOL("", '\0') {
		@Override
		public long toByte(long len) {
			return len;
		}
	},
	
	BYTE("B", 'B') {
		@Override
		public long toByte(long len) {
			return len;
		}
		
		@Override
		public long toKiloByte(long len) {
			return BigDecimalUtils.division(len, DataSize.B1).longValue();
		}
		
		@Override
		public long toMegaByte(long len) {
			return BigDecimalUtils.division(len, DataSize.B2).longValue();
		}
		
		@Override
		public long toGigaByte(long len) {
			return BigDecimalUtils.division(len, DataSize.B3).longValue();
		}
		
		@Override
		public long toTeraByte(long len) {
			return BigDecimalUtils.division(len, DataSize.B4).longValue();
		}
		
		@Override
		public long toPetaByte(long len) {
			return BigDecimalUtils.division(len, DataSize.B5).longValue();
		}
	},
	
	KB("KB", 'K') {
		@Override
		public long toByte(long len) {
			return BigDecimalUtils.multiply(len, DataSize.B1).longValue();
		}
		
		@Override
		public long toKiloByte(long len) {
			return len;
		}
		
		@Override
		public long toMegaByte(long len) {
			return BigDecimalUtils.division(len, DataSize.B1).longValue();
		}
		
		@Override
		public long toGigaByte(long len) {
			return BigDecimalUtils.division(len, DataSize.B2).longValue();
		}
		
		@Override
		public long toTeraByte(long len) {
			return BigDecimalUtils.division(len, DataSize.B3).longValue();
		}
		
		@Override
		public long toPetaByte(long len) {
			return BigDecimalUtils.division(len, DataSize.B4).longValue();
		}
	},
	
	MB("MB", 'M') {
		@Override
		public long toByte(long len) {
			return BigDecimalUtils.multiply(len, DataSize.B2).longValue();
		}
		
		@Override
		public long toKiloByte(long len) {
			return BigDecimalUtils.multiply(len, DataSize.B1).longValue();
		}
		
		@Override
		public long toMegaByte(long len) {
			return len;
		}
		
		@Override
		public long toGigaByte(long len) {
			return BigDecimalUtils.division(len, DataSize.B1).longValue();
		}
		
		@Override
		public long toTeraByte(long len) {
			return BigDecimalUtils.division(len, DataSize.B2).longValue();
		}
		
		@Override
		public long toPetaByte(long len) {
			return BigDecimalUtils.division(len, DataSize.B3).longValue();
		}
	},
	
	GB("GB", 'G') {
		@Override
		public long toByte(long len) {
			return BigDecimalUtils.multiply(len, DataSize.B3).longValue();
		}
		
		@Override
		public long toKiloByte(long len) {
			return BigDecimalUtils.multiply(len, DataSize.B2).longValue();
		}
		
		@Override
		public long toMegaByte(long len) {
			return BigDecimalUtils.multiply(len, DataSize.B1).longValue();
		}
		
		@Override
		public long toGigaByte(long len) {
			return len;
		}
		
		@Override
		public long toTeraByte(long len) {
			return BigDecimalUtils.division(len, DataSize.B1).longValue();
		}
		
		@Override
		public long toPetaByte(long len) {
			return BigDecimalUtils.division(len, DataSize.B2).longValue();
		}
	},
	
	TB("TB", 'T') {
		@Override
		public long toByte(long len) {
			return BigDecimalUtils.multiply(len, DataSize.B4).longValue();
		}
		
		@Override
		public long toKiloByte(long len) {
			return BigDecimalUtils.multiply(len, DataSize.B3).longValue();
		}
		
		@Override
		public long toMegaByte(long len) {
			return BigDecimalUtils.multiply(len, DataSize.B2).longValue();
		}
		
		@Override
		public long toGigaByte(long len) {
			return BigDecimalUtils.multiply(len, DataSize.B1).longValue();
		}
		
		@Override
		public long toTeraByte(long len) {
			return len;
		}
		
		@Override
		public long toPetaByte(long len) {
			return BigDecimalUtils.division(len, DataSize.B1).longValue();
		}
	},
	
	PB("PB", 'P') {
		@Override
		public long toByte(long len) {
			return BigDecimalUtils.multiply(len, DataSize.B5).longValue();
		}
		
		@Override
		public long toKiloByte(long len) {
			return BigDecimalUtils.multiply(len, DataSize.B4).longValue();
		}
		
		@Override
		public long toMegaByte(long len) {
			return BigDecimalUtils.multiply(len, DataSize.B3).longValue();
		}
		
		@Override
		public long toGigaByte(long len) {
			return BigDecimalUtils.multiply(len, DataSize.B2).longValue();
		}
		
		@Override
		public long toTeraByte(long len) {
			return BigDecimalUtils.multiply(len, DataSize.B1).longValue();
		}
		
		@Override
		public long toPetaByte(long len) {
			return len;
		}
	};
	
	
	/** 长度单位 */
	private String value;
	/** 长度单位标记位 */
	private char mark;
	
	/**	
	 * 	构造函数-自定义长度单位
	 * 	
	 * 	@author Pan
	 * 	@param 	value	长度单位
	 * 	@param 	c		长度单位标记位
	 */
	DataSizeUnit(String value, char c) {
		this.value = value;
		this.mark = c;
	}

	/**	
	 * 	获取长度单位
	 * 	
	 * 	@author Pan
	 * 	@return	String
	 */
	public String value() {
		return value;
	}
	
	/**	
	 * 	获取标记位
	 * 	
	 * 	@author Pan
	 * 	@return	char
	 */
	public char getMark() {
		return mark;
	}

	/**	
	 * 	根据字符串获取长度单位枚举
	 * 	
	 * 	@author Pan
	 * 	@param 	str	字符串
	 * 	@return	DataSizeUnit
	 */
	public static DataSizeUnit getUnit(String str) {
		Assert.isNotEmpty(str);
		int length = str.length();
		
		if (length == 1) {
			if (ValidParam.isNumber(str.charAt(length - 1))) {
				return NO_SYMBOL;
			}
			throw new IllegalArgumentException(StringUtils.format("parameter error [{}]", str));
		}
		
		char end = str.charAt(length - 1);
		char end2 = str.charAt(length - 2);
		
		if (ValidParam.isNumber(end)) {
			return NO_SYMBOL;
		}
		
		if (end == 'B' || end == 'b') {
			if (ValidParam.isNumber(end2)) {
				return BYTE;
			}
			
			DataSizeUnit[] values = DataSizeUnit.values();
			for (int i = 0; i < values.length; i++) {
				DataSizeUnit dataSizeUnit = values[i];
				if (dataSizeUnit.getMark() == end2 || dataSizeUnit.getMark() + 32 == end2) {
					return dataSizeUnit;
				}
			}
		}
		throw new UnknownTypeException(StringUtils.format("unsupported unit types [{}]", str));
	}
	
	/**
	 * 	将当前长度转化成Byte长度
	 * 	<br>长度单位枚举内部实现了转化流程机制
	 * 	
	 * 	@author Pan
	 * 	@param 	len	 数据长度
	 * 	@return	long
	 */
	public long toByte(long len) {
		throw new AbstractMethodError("not found toByte method");
	}
	
	/**
	 * 	将当前长度转化成KiloByte长度
	 * 	<br>长度单位枚举内部实现了转化流程机制
	 * 	
	 * 	@author Pan
	 * 	@param 	len	 数据长度
	 * 	@return	long
	 */
	public long toKiloByte(long len) {
		throw new AbstractMethodError("not found toKiloByte method");
	}
	
	/**
	 * 	将当前长度转化成MegaByte长度
	 * 	<br>长度单位枚举内部实现了转化流程机制
	 * 	
	 * 	@author Pan
	 * 	@param 	len	 数据长度
	 * 	@return	long
	 */
	public long toMegaByte(long len) {
		throw new AbstractMethodError("not found toMegaByte method");
	}
	
	/**
	 * 	将当前长度转化成GigaByte长度
	 * 	<br>长度单位枚举内部实现了转化流程机制
	 * 	
	 * 	@author Pan
	 * 	@param 	len	 数据长度
	 * 	@return	long
	 */
	public long toGigaByte(long len) {
		throw new AbstractMethodError("not found toGigaByte method");
	}
	
	/**
	 * 	将当前长度转化成TeraByte长度
	 * 	<br>长度单位枚举内部实现了转化流程机制
	 * 	
	 * 	@author Pan
	 * 	@param 	len	 数据长度
	 * 	@return	long
	 */
	public long toTeraByte(long len) {
		throw new AbstractMethodError("not found toTeraByte method");
	}
	
	/**
	 * 	将当前长度转化成PetaByte长度
	 * 	<br>长度单位枚举内部实现了转化流程机制
	 * 	
	 * 	@author Pan
	 * 	@param 	len	 数据长度
	 * 	@return	long
	 */
	public long toPetaByte(long len) {
		throw new AbstractMethodError("not found toPetaByte method");
	}
}
